package cn.myspringboot.service.impl;

import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.myspringboot.constants.Constants;
import cn.myspringboot.domain.OpenIdResult;
import cn.myspringboot.mapper.PermissionMapper;
import cn.myspringboot.pojo.bto.AdminLoginBto;
import cn.myspringboot.pojo.bto.LoginBto;
import cn.myspringboot.pojo.domain.Login;
import cn.myspringboot.mapper.LoginMapper;
import cn.myspringboot.pojo.domain.Permission;
import cn.myspringboot.pojo.vo.LoginSuccessVo;
import cn.myspringboot.service.ILoginService;
import cn.myspringboot.template.WechatLoginTemplate;
import cn.myspringboot.utils.AssertUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author cym
 * @since 2025-03-28
 */
@Service
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {

    @Autowired
    private LoginMapper loginMapper;
    @Autowired
    private WechatLoginTemplate wechatLoginTemplate;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    @Transactional
    public LoginSuccessVo login(LoginBto loginBto) {
        //前端携带code到后端 后端获取openid以及type
        String code = loginBto.getCode();
        OpenIdResult openId = wechatLoginTemplate.getOpenId(code);
        //没有openid就注册
        AssertUtil.isNotEmpty(openId.getOpenId(),"微信ID不可为空");
        //有就执行登录将id设置进去
        Login login = loginMapper.selectOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getOpenId, openId.getOpenId())
                .eq(Login::getType, loginBto.getType()));
        AssertUtil.isNotNull(login,"请先注册");
        //执行登录
//        StpUtil.login(login.getId());
        LoginSuccessVo loginSuccessVo = getLoginSuccessVo(login);

        //返回结果给前端
        return loginSuccessVo;
    }

    private LoginSuccessVo getLoginSuccessVo(Login login) {
        SaTokenInfo saTokenInfo = saTokenLogin(login);
        //封装登录信息
        LoginSuccessVo loginSuccessVo = new LoginSuccessVo();
        loginSuccessVo.setAvatar(login.getAvatar());
        loginSuccessVo.setNickName(login.getNickName());
        loginSuccessVo.setPhone(login.getPhone());

        //通过satoken获取token
        loginSuccessVo.setToken(saTokenInfo);

        List<String> loginPermissions = null;
        if(login.getUsername().equals(Constants.System.ADMIN)){
            List<Permission> permissions = permissionMapper.selectList(new LambdaQueryWrapper<>());
            loginPermissions = permissions.stream().map(Permission::getSn).collect(Collectors.toList());
        }else {
            loginPermissions  = loginMapper.getLoginPermission(login.getId());
        }

        //将用户的权限和角色保存到redis中
        List<String> roles = loginMapper.getLoginByRole(login.getId());
        List<String> permissions = loginMapper.getLoginPermission(login.getId());
        redisTemplate.opsForValue().set(Constants.redis.ROLE+ login.getId().toString(),roles );
        redisTemplate.opsForValue().set(Constants.redis.PERMISSION+ login.getId().toString(),permissions);
        //保存登录信息以及权限
        login.setOpenId("");
        login.setPassword("");
        loginSuccessVo.setLogin(login);
        loginSuccessVo.setPermissions(permissions);
        return loginSuccessVo;
    }

    @Override
    public LoginSuccessVo adminLogin(AdminLoginBto adminLoginBto) {
        //判断用户是否存在
        String username = adminLoginBto.getUsername();
        Login login = loginMapper.selectOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getUsername, username)
                .or()
                .eq(Login::getPhone, username)
                .eq(Login::getType, adminLoginBto.getType()));
        AssertUtil.isNotNull(login,"用户或密码错误");
        //判断密码
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        bCryptPasswordEncoder.matches(adminLoginBto.getPassword(),login.getPassword());
        LoginSuccessVo loginSuccessVo = getLoginSuccessVo(login);
        return loginSuccessVo;
    }

    //执行SaToken登录逻辑
    public SaTokenInfo saTokenLogin(Login login){
        StpUtil.login(login.getId(), SaLoginConfig
                //根据需要封装扩展参数
                .setExtra("username", login.getUsername())
                .setExtra("type", login.getType())
                .setExtra("avatar", login.getAvatar())
                .setExtra("admin", login.getAdmin())
                .setExtra("nickName", login.getNickName())
                //加载权限
                .setExtra("permissions", StpUtil.getPermissionList(login.getId()))
                .setExtra("roles", StpUtil.getRoleList(login.getId()))
                .setExtra("openId", login.getOpenId()));
        return StpUtil.getTokenInfo();
    }
}
